package com.och.mrcp.service.impl;

import com.alibaba.nls.client.AccessToken;
import com.alibaba.nls.client.protocol.NlsClient;
import com.och.mrcp.config.EngineConfig;
import com.och.mrcp.service.VoiceSessionService;
import com.och.mrcp.util.DateUtil;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.concurrent.*;

/**
 * 阿里云语音服务会话管理实现
 * 管理阿里云ASR会话的完整生命周期
 * 集成了NLS客户端管理和会话管理功能
 * @author danmo
 */
@Slf4j
@Service("aliyunVoiceSessionService")
public class AliyunVoiceSessionService implements VoiceSessionService {
    
    // 引擎配置
    @Autowired
    private EngineConfig engineConfig;

    // NLS客户端管理
    private NlsClient nlsClient;
    private AccessToken accessToken;
    private boolean isInitialized = false;
    
    // 会话存储：sessionId -> AliyunAsrSession
    private final ConcurrentHashMap<String, AliyunAsrSession> sessions = new ConcurrentHashMap<>();
    
    // 定时任务执行器，用于会话清理
    // 优化为多线程调度器，支持更多并发会话管理
    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(8, r -> {
        Thread t = new Thread(r, "AliyunVoiceSession-Scheduler");
        t.setDaemon(true);
        return t;
    });
    
    public AliyunVoiceSessionService() {
        log.info("Initializing Aliyun Voice Session Service...");
        // 启动定时任务：每5分钟清理过期会话
        scheduler.scheduleAtFixedRate(this::cleanupExpiredSessions, 5, 5, TimeUnit.MINUTES);
    }
    
    @Override
    public CompletableFuture<Void> createRecognitionSession(String sessionId, 
                                                           EngineConfig.RecognitionConfig config,
                                                           SessionCallback callback) {
        log.info("AliyunVoiceSessionService: createRecognitionSession called for session: {}", sessionId);
        
        return CompletableFuture.runAsync(() -> {
            try {
                log.info("AliyunVoiceSessionService: Checking if service is available...");

                if (!isAvailable()) {
                    throw new IllegalStateException("Aliyun Voice Service is not available after waiting");
                }
                log.info("AliyunVoiceSessionService: Service is available, proceeding with session creation...");
                
                // 检查会话是否已存在
                if (sessions.containsKey(sessionId)) {
                    log.warn("ASR session already exists: {}, cleaning up old session", sessionId);
                    AliyunAsrSession existingSession = sessions.remove(sessionId);
                    if (existingSession != null) {
                        existingSession.cleanup();
                    }
                }
                
                log.info("Creating ASR session: {}", sessionId);
                
                // 检查AccessToken是否过期，如果过期则刷新
                checkAndRefreshAccessToken();
                
                // 获取必要资源
                String appKey = engineConfig.getAliyun().getAppKey();
                
                if (nlsClient == null || appKey == null) {
                    throw new IllegalStateException("Failed to get NLS client or app key");
                }
                
                // 创建新会话
                AliyunAsrSession session = new AliyunAsrSession(sessionId, appKey, nlsClient, config, callback);
                sessions.put(sessionId, session);
                
                log.info("ASR session created: {}, total sessions: {}", sessionId, sessions.size());
                
            } catch (Exception e) {
                log.error("Failed to create ASR session: {}", sessionId, e);
                throw new RuntimeException("Failed to create ASR session: " + sessionId, e);
            }
        });
    }
    
    @Override
    public CompletableFuture<Void> startRecognitionSession(String sessionId) {
        AliyunAsrSession session = sessions.get(sessionId);
        if (session == null) {
            return CompletableFuture.failedFuture(
                new IllegalArgumentException("ASR session not found: " + sessionId));
        }
        
        return session.start();
    }
    
    @Override
    public CompletableFuture<Void> sendAudioData(String sessionId, byte[] audioData) {
        log.debug("AliyunVoiceSessionService: Attempting to send audio data for session: {}, data size: {}", 
                sessionId, audioData != null ? audioData.length : "null");
        
        // 验证音频数据
        if (audioData == null) {
            log.warn("AliyunVoiceSessionService: Received null audio data for session: {}", sessionId);
            return CompletableFuture.completedFuture(null); // 不是错误，直接忽略
        }
        
        if (audioData.length == 0) {
            log.debug("AliyunVoiceSessionService: Received empty audio data for session: {}", sessionId);
            return CompletableFuture.completedFuture(null); // 空数据，直接忽略
        }
        
        AliyunAsrSession session = sessions.get(sessionId);
        if (session == null) {
            log.error("AliyunVoiceSessionService: ASR session not found: {}, available sessions: {}", 
                    sessionId, sessions.keySet());
            return CompletableFuture.failedFuture(
                new IllegalArgumentException("ASR session not found: " + sessionId));
        }
        
        try {
            return session.sendAudioData(audioData);
        } catch (Exception e) {
            log.error("Failed to send audio data to session: {}, data size: {}", 
                    sessionId, audioData != null ? audioData.length : "null", e);
            return CompletableFuture.failedFuture(e);
        }
    }
    
    @Override
    public CompletableFuture<Void> stopRecognitionSession(String sessionId) {
        AliyunAsrSession session = sessions.get(sessionId);
        if (session == null) {
            return CompletableFuture.failedFuture(
                new IllegalArgumentException("ASR session not found: " + sessionId));
        }
        
        return session.stop().thenApply(result -> null);
    }
    
    @Override
    public CompletableFuture<Void> destroyRecognitionSession(String sessionId) {
        AliyunAsrSession session = sessions.remove(sessionId);
        if (session != null) {
            session.cleanup();
            log.info("ASR session destroyed: {}, remaining sessions: {}", sessionId, sessions.size());
        }
        return CompletableFuture.completedFuture(null);
    }
    
    @Override
    public SessionState getSessionState(String sessionId) {
        AliyunAsrSession session = sessions.get(sessionId);
        return session != null ? session.getState() : null;
    }
    
    @Override
    public boolean sessionExists(String sessionId) {
        return sessions.containsKey(sessionId);
    }
    
    @Override
    public String getProviderName() {
        return "Aliyun";
    }
    
    /**
     * 检查服务是否可用
     */
    public boolean isAvailable() {
        log.info("AliyunVoiceSessionService: Checking service availability...");
        return isInitialized && nlsClient != null;
    }
    
    @Override
    public void cleanupAllSessions() {
        log.info("Cleaning up Aliyun Voice Session Service...");
        
        // 清理所有会话
        sessions.forEach((sessionId, session) -> {
            try {
                session.cleanup();
            } catch (Exception e) {
                log.warn("Error cleaning up session: {}", sessionId, e);
            }
        });
        sessions.clear();
        
        // 关闭定时任务
        if (scheduler != null && !scheduler.isShutdown()) {
            scheduler.shutdown();
            try {
                if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) {
                    scheduler.shutdownNow();
                }
            } catch (InterruptedException e) {
                scheduler.shutdownNow();
                Thread.currentThread().interrupt();
            }
        }
        
        // 关闭NLS客户端
        if (nlsClient != null) {
            try {
                nlsClient.shutdown();
                log.info("Aliyun NLS client shutdown completed");
            } catch (Exception e) {
                log.warn("Error during NLS client shutdown: {}", e.getMessage());
            }
        }
        
        isInitialized = false;
    }


    /**
     * 检查AccessToken是否过期，如果过期则自动刷新
     */
    private synchronized void checkAndRefreshAccessToken() {
        if (accessToken == null) {
            log.warn("AccessToken is null, will be initialized when needed");
            return;
        }
        
        try {
            // 计算剩余过期时间（秒）
            long expireTime = accessToken.getExpireTime() - DateUtil.currentSeconds();
            
            log.debug("AccessToken expiry check: expires in {} seconds", expireTime);
            
            // 如果token在60秒内过期，则提前刷新
            if (expireTime <= 60) {
                log.info("AccessToken will expire in {} seconds, refreshing token", expireTime);
                
                // 重新获取token
                EngineConfig.AliyunConfig aliyunConfig = engineConfig.getAliyun();
                String accessKeyId = aliyunConfig.getAccessKeyId();
                String accessKeySecret = aliyunConfig.getAccessKeySecret();
                
                if (accessKeyId == null || accessKeySecret == null) {
                    throw new IllegalStateException("Aliyun credentials not available for token refresh");
                }
                
                // 创建新的AccessToken
                AccessToken newAccessToken = new AccessToken(accessKeyId, accessKeySecret);
                newAccessToken.apply();
                String newToken = newAccessToken.getToken();
                
                // 更新accessToken引用
                this.accessToken = newAccessToken;
                
                // 重新创建NLS客户端
                String asrEndpoint = aliyunConfig.getNlsGatewayUrl();
                if (nlsClient != null) {
                    nlsClient.setToken(newToken);
                }else {
                    if (asrEndpoint != null && !asrEndpoint.isEmpty()) {
                        nlsClient = new NlsClient(asrEndpoint, newToken);
                    } else {
                        nlsClient = new NlsClient(newToken);
                    }
                }
                log.info("AccessToken refreshed successfully, new expiry: {} (expires in {} seconds)", 
                        newAccessToken.getExpireTime(), 
                        newAccessToken.getExpireTime() - DateUtil.currentSeconds());
            } else {
                log.debug("AccessToken is still valid, expires in {} seconds", expireTime);
            }
            
        } catch (Exception e) {
            log.error("Failed to refresh AccessToken: {}", e.getMessage(), e);
            throw new RuntimeException("AccessToken refresh failed", e);
        }
    }
    
    /**
     * 初始化阿里云服务
     */
    @PostConstruct
    private void initializeService() {
        try {
            EngineConfig.AliyunConfig aliyunConfig = engineConfig.getAliyun();
            
            String accessKeyId = aliyunConfig.getAccessKeyId();
            String accessKeySecret = aliyunConfig.getAccessKeySecret();
            String appKey = aliyunConfig.getAppKey();
            String asrEndpoint = aliyunConfig.getNlsGatewayUrl();
            
            if (accessKeyId == null || accessKeySecret == null || appKey == null) {
                return;
            }
            
            log.info("Initializing Aliyun NLS client...");
            
            // 获取访问令牌
            accessToken = new AccessToken(accessKeyId, accessKeySecret);
            accessToken.apply();
            String token = accessToken.getToken();

            log.info("Access token obtained successfully, expires at: {}", accessToken.getExpireTime());
            
            // 创建NLS客户端
            if (asrEndpoint != null && !asrEndpoint.isEmpty()) {
                nlsClient = new NlsClient(asrEndpoint, token);
            } else {
                nlsClient = new NlsClient(token);
            }
            
            log.info("Aliyun Voice Service initialized successfully");
            log.info("Region: {}, ASR Endpoint: {}, App Key: {}",
                aliyunConfig.getRegion(), asrEndpoint,
                appKey.substring(0, Math.min(8, appKey.length())) + "...");
            isInitialized = true;
        } catch (Exception e) {
            log.error("Failed to initialize Aliyun Voice Service: {}", e.getMessage(), e);
        }
    }



    /**
     * 获取活跃会话数量
     */
    @Override
    public int getActiveSessionCount() {
        return (int) sessions.values().stream()
                .filter(session -> session.getState() == SessionState.ACTIVE)
                .count();
    }
    
    /**
     * 清理过期的会话
     */
    private void cleanupExpiredSessions() {
        long currentTime = System.currentTimeMillis();
        long maxSessionAge = 30 * 60 * 1000; // 30分钟
        
        sessions.entrySet().removeIf(entry -> {
            AliyunAsrSession session = entry.getValue();
            boolean shouldRemove = (currentTime - session.getStartTime()) > maxSessionAge;
            
            if (shouldRemove) {
                log.info("Cleaning up expired ASR session: {}", entry.getKey());
                session.cleanup();
            }
            
            return shouldRemove;
        });
    }
    
    /**
     * 获取服务配置信息
     */
    public String getServiceInfo() {
        return String.format("AliyunVoiceSessionService{totalSessions=%d, activeSessions=%d, initialized=%s, region=%s}",
            sessions.size(), getActiveSessionCount(), isInitialized, engineConfig.getAliyun().getRegion());
    }
    
    /**
     * 获取NLS客户端
     */
    public NlsClient getNlsClient() {
        return nlsClient;
    }
    
    /**
     * 获取引擎配置
     */
    public EngineConfig getEngineConfig() {
        return engineConfig;
    }
    
    @PreDestroy
    public void destroy() {
        cleanupAllSessions();
    }
}
